package br.com.arg.aplica.controller;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.ejb.Stateful;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.inject.Inject;
import javax.inject.Named;

import br.com.arg.aplica.model.Atributo;
import br.com.arg.aplica.model.Dominio;
import br.com.arg.aplica.model.Campo;
import br.com.arg.aplica.model.CasoDeUso;
import br.com.arg.aplica.model.Classe;
import br.com.arg.aplica.model.Componente;
import br.com.arg.aplica.model.Mensagem;
import br.com.arg.aplica.model.Pendencia;
import br.com.arg.aplica.model.Regra;
import br.com.arg.aplica.model.Sistema;
import br.com.arg.aplica.model.Tela;
import br.com.arg.aplica.util.StatusSistema;
import br.com.arg.aplica.util.Utils;
import br.com.arg.aplica.util.ValidadorBean;

// The @Stateful annotation eliminates the need for manual transaction demarcation
@Stateful
// The @Model stereotype is a convenience mechanism to make this a
// request-scoped bean that has an
// EL name
// Read more about the @Model stereotype in this FAQ:
// http://sfwk.org/Documentation/WhatIsThePurposeOfTheModelAnnotation
@Named 
@SessionScoped 
public class SistemaRegistration extends BaseRegistracao {

	@Inject
	private Event<Sistema> sistemaEventSrc;
	
	@Inject 
	private List<Sistema> sistemas;
	
	private Sistema newSistema;
	@Produces @Named
	public Sistema getNewSistema() {
		return newSistema;
	}

//	Id do sistema - usado para buscar sistema	
	private String idSistema;
	public String getIdSistema() {
		return idSistema;
	}

	public void setIdSistema(String idSistema) {
		this.idSistema = idSistema;
		buscaSistema();
	}

	public String registrar() throws Exception {
		if (consiteSistema(newSistema))
			registrarComPendencias();
		
		return null;
	}
	
	public String registrarComPendencias() throws Exception {
		em.merge(newSistema);
		
		log.info(String.format("Registering aplica=%s", newSistema.getNome()));
		facesContext.addMessage(null, new FacesMessage(
				FacesMessage.SEVERITY_INFO, "Registered!",
				"Registration successful"));

		sistemaEventSrc.fire(newSistema);

		inicializa();
		
		return null;
	}
		
	private boolean consiteSistema(Sistema sistema) {
		try {
			ValidadorBean validador = new ValidadorBean();
			validador.limpaMensagens();

			validador.validar(sistema);

			// Casos De Uso
			for (CasoDeUso cu : sistema.getCasosDeUso()) {
				validador.validar(cu);
				for (Classe c : cu.getClasses()) {
					validador.validar(c);
					for (Atributo atr : c.getAtributos()){
						validador.validar(atr);
						for (Dominio d: atr.getDominios())
							validador.validar(d);
						for (Regra regra : atr.getRegras())
							validador.validar(regra);
					}
					for (Regra regra : c.getRegras())
						validador.validar(regra);
				}
				for (Tela t : cu.getTelas()) {
					validador.validar(t);
					for (Componente cmp : t.getComponentes()){
						validador.validar(cmp);
						for (Dominio d: cmp.getDominios())
							validador.validar(d);
						for (Regra regra : cmp.getRegras())
							validador.validar(regra);
					}
				}
				for (Mensagem m : cu.getMensagens()) {
					validador.validar(m);
					for (Campo cpo : m.getCampos()){
						validador.validar(cpo);
					}
				}
			}
		
			if (validador.getMensagens().size() > 0) {
				sistema.getPendencias().clear();
				for (String strPend : validador.getMensagens()) {
					Pendencia pend = new Pendencia();
					pend.setDataPendencia(Utils.setData("hoje"));
					pend.setPendencia(strPend);
					pend.setStatus(StatusSistema.Iniciando);
					sistema.getPendencias().add(pend);
				}
				facesContext.addMessage(null, new FacesMessage(
						FacesMessage.SEVERITY_ERROR,
						"Erro na validação do sistema!",
						"Erro na validação do sistema."));
				return false;
			}
		} catch (Exception ex) {
			facesContext.addMessage(null, new FacesMessage(
					FacesMessage.SEVERITY_ERROR,
					"Erro na validação do sistema!",
					"Erro na validação do sistema."));
			return false;
		}

		return true;
	}
	

	public void novoSistema() {
		inicializa();
	}
	
	public void buscaSistema() {
		newSistema = em.find(Sistema.class, Long.parseLong(idSistema, 10));
		System.out.println("++++++++++++++++++++++++>>> Buscando aplica " + newSistema.getNome());
	}
	
	public String exclua() throws Exception {
		Sistema apl = em.find(Sistema.class, Long.parseLong(idSistema, 10));
		System.out.println("++++++++++++++++++++++++>>> Excluindo aplica " + apl.getNome());

		em.remove(apl);
		
		facesContext.addMessage(null, new FacesMessage(
				FacesMessage.SEVERITY_INFO, "Registered!",
				"Registration successful"));

		sistemaEventSrc.fire(newSistema);	

		return null;		
	}
	
//	Id do casoDeUso - usado para buscar casoDeUso	
	private String idCasoDeUso;
	public String getIdCasoDeUso() {
		return idCasoDeUso;
	}

	public void setIdCasoDeUso(String idCasoDeUso) {
		this.idCasoDeUso = idCasoDeUso;
	}

	private CasoDeUso newCasoDeUso;
	@Produces @Named
	public CasoDeUso getNewCasoDeUso() {
		return newCasoDeUso;
	}

	public void buscaCasoDeUso() {
		newCasoDeUso = em.find(CasoDeUso.class, Long.parseLong(idCasoDeUso, 10));
		System.out.println("++++++++++++++++++++++++>>> Buscando newCasoDeUso " + newCasoDeUso.getNome());
	}
		
	public void addCasoDeUso() {
		newSistema.getCasosDeUso().add(newCasoDeUso);
		System.out.println("+++++++++++++++++++ add caso de uso" + newSistema.getNome() + " cu " + newCasoDeUso.getNome());
		newCasoDeUso = new CasoDeUso();
		facesContext.addMessage(null, new FacesMessage(
				FacesMessage.SEVERITY_INFO, "New UC added",
				"Registration successful"));
	}
	
	@PostConstruct
	public void inicializa() {
		newSistema = new Sistema();
		newCasoDeUso = new CasoDeUso();
	}
}
